home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Developer
/
Eval
/
Source
/
Eval.m
< prev
next >
Wrap
Text File
|
1992-09-17
|
17KB
|
575 lines
#import "Eval.h"
#import "EvalWrap.h"
#import "GraphicsView.h"
#import "CString.h"
#import <appkit/Text.h>
#import <appkit/ScrollView.h>
#import <appkit/Listener.h>
#import <appkit/Pasteboard.h>
#import <appkit/NXSplitView.h>
#import <appkit/NXBrowser.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/Matrix.h>
#import <appkit/OpenPanel.h>
#import <appkit/Font.h>
#import <appkit/Pasteboard.h>
#import <defaults/defaults.h>
#import <objc/List.h>
#import <objc/objc-load.h>
#import <objc/error.h>
#import <streams/streams.h>
#import <sys/stat.h>
#import <sys/stat.h>
#import <libc.h>
#import <ctype.h>
#import <dpsclient/psops.h>
#import <dpsclient/dpsclient.h>
#import <streams/streams.h>
id text, graphics ;
static NXDefaultsVector evalDefaults =
{ {"NXFont","Ohlfs"},
{"NXFontSize","11.0"},
{"Frame","100.0 100.0 300.0 300.0"},
{"GraphicsSize","400.0 400.0"},
{"CompilerSwitches",""},
{"Libraries","/lib/libsys_s.a /usr/lib/libNeXT_s.a"},
{NULL}
} ;
// archive (library) extension
const char *libTypes[] =
{ "a",
NULL
} ;
@implementation Eval: Application
{ id transcriptWindow ;
id splitView ;
id transcriptText ;
id transcriptGraphics ;
id textScrollView ;
id graphicsScrollView ;
// pref thingies
id fontName ;
id fontSize ;
id graphicsSize ;
id compilerSwitches ;
id libBrowser ;
id libList ;
}
+ clearGraphics ;
{ return [graphics clear] ;
}
+ clearText ;
{ return [text setText: ""] ;
}
+ printf: (char *) format, ... ;
{ // format (as in printf) and print to the transcript
NXStream *aStream ;
char *textBuf ;
int textLen, maxLen ;
va_list argList ;
aStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
va_start(argList, format) ;
NXVPrintf(aStream, format, argList) ;
NXGetMemoryBuffer(aStream, &textBuf, &textLen, &maxLen);
textLen = [text textLength] ;
[text setSel: textLen :textLen] ;
[text replaceSel: textBuf] ;
NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
[[text window] orderFront: self] ;
return self ;
}
void SwitchContextsWithFocus(DPSContext newContext)
{ // borowsed from YAP: switch to newContext in order to
// protect the main context
float c1x, c1y, c2x, c2y;
float winCTM[6];
int realWinNum;
GetFocus(&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum);
DPSSetContext(newContext);
ReFocus(realWinNum, winCTM, c1x, c1y, c2x, c2y);
}
+ ps: (char *) format, ... ;
{ // format (as in printf) and send to windowserver.
// Done in a separate context to provide good
// error handling and recovery. The idea is stolen
// from Yap.
NXStream *dataStream, *errorStream ;
char *dataBuffer ;
va_list argList ;
int len, maxLen ;
NXHandler exception;
static DPSContext NUContext = NULL; // The second context
DPSContext curContext = DPSGetCurrentContext();
[[graphics image] lockFocus] ;
if(!NUContext) // create the second context
{ const char *app = [NXApp appName];
NUContext = DPSCreateContext(NXGetDefaultValue(app, "NXHost"),
NXGetDefaultValue(app, "NXPSName"), NULL, NULL);
DPSSetContext(curContext);
}
dataStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
va_start(argList, format) ;
NXVPrintf(dataStream, format, argList) ;
NXPutc(dataStream,'\n') ;
NXGetMemoryBuffer(dataStream, &dataBuffer, &len, &maxLen);
SwitchContextsWithFocus(NUContext);
exception.code = 0 ;
NX_DURING
DPSWriteData(NUContext,dataBuffer,len) ;
NXPing ();
NX_HANDLER
exception = NXLocalHandler ;
NX_ENDHANDLER
DPSSetContext(curContext);
NXCloseMemory(dataStream,NX_FREEBUFFER) ;
if(exception.code)
{ NXRunAlertPanel("Eval","Postcript errors in message\n"
"to [ps...] : see transcript",NULL,NULL,NULL) ;
errorStream = NXOpenMemory(NULL,0,NX_WRITEONLY);
DPSPrintErrorToStream(errorStream,
(DPSBinObjSeq) exception.data2);
NXPrintf(errorStream,"\n\0") ;
NXFlush(errorStream);
NXGetMemoryBuffer(errorStream, &dataBuffer, &len, &maxLen);
[Eval printf: "%s\n", dataBuffer] ;
NXCloseMemory(errorStream, NX_FREEBUFFER);
DPSDestroyContext(NUContext);
NUContext = NULL;
}
[[graphics image] unlockFocus] ;
[[graphics window] display] ;
[[graphics window] orderFront: self] ;
return self;
}
+ startPS ;
{ // lock focus on graphics image
[[graphics image] lockFocus] ;
return self ;
}
+ stopPS ;
{ // unlock focus on graphics image ; display
// the graphics
[[graphics image] unlockFocus] ;
[graphics display] ;
[[graphics window] orderFront: self] ;
return self ;
}
- appDidInit: sender ;
{ // set myself as the services delegate
[[self appListener] setServicesDelegate: self] ;
return self ;
}
- appendFileToTranscript: (char *) fileName ;
{ // append the text of the indicated file to the transcript
char *aStr ;
struct stat statBuf ;
int fd ;
if(!(fd = open(fileName,O_RDONLY)))
{ NXRunAlertPanel("Eval","Cannot open: %c",NULL,NULL,NULL,fileName) ;
return self ;
}
fstat(fd,&statBuf) ;
aStr = malloc(statBuf.st_size + 1) ;
read(fd,aStr,statBuf.st_size) ;
aStr[statBuf.st_size] = '\0' ;
[Eval printf: aStr] ;
close(fd) ;
free(aStr) ;
return self ;
}
- (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
{ // delegate method for browser object
return [libList count] ;
}
- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
{ [cell setStringValue: [[libList objectAt: row] cString]] ;
[cell setLeaf: YES] ;
return self ;
}
- clearTranscriptGraphics: sender ;
{ return [Eval clearGraphics] ;
}
- clearTranscriptText: sender ;
{ return [Eval clearText] ;
}
- evalObjC: (char *) text length: (int) len ;
{ // evaluate objc in text (not necessarily null-terminated)...
// of length len
char textBuf[len+1] , aStr[128] ;
char *header, *body, *cursor ;
int moduleKnt ;
char tmpFile[20] = "EvalXXXXXX" ;
NXStream *aStream ;
FILE *fp ;
int i, textLen, maxLen ;
// copy the message so we can sever it in two
strncpy(textBuf,text,len) ;
// don't know if text is null terminated
textBuf[len] = '\0' ;
// find out if we have any header
header = body = textBuf ;
// move header pointer to start of header
while(isspace(*header))
header++ ; // scan past any initial whiteSpace
if(*header == '#') // then we have a header
{ // move body pointer to start of body
body = header ;
while(strncmp(body++,"\n\n", 2)) // "empty" line is end of header
{ if(*body == '\0') // then header ends without a body
{ NXRunAlertPanel("Eval", "No body to evaluate.\n",
NULL,NULL,NULL) ;
return self ;
}
}
*body++ = '\0' ; // make body point 1 char beyond end of header,
// then sever textBuf into 2 strings (header and body) ;
}
else
header = "" ; // no header at all
// The string tmpFile is both the name of the class we will create
// and the name of the file, within /tmp, it will live in...
mktemp(tmpFile) ;
sprintf(aStr,"/tmp/%s.m",tmpFile) ;
fp = fopen(aStr,"w+") ;
fprintf(fp,
"%s\n"
"#import <objc/Object.h>\n"
"@interface Eval: Object\n"
"+ clearGraphics ;\n"
"+ clearText ;\n"
"+ printf: (char *) format, ... ;\n"
"+ ps: (char *) format, ... ;\n"
"+ startPS ;\n"
"+ stopPS ;\n"
"@end\n"
"@interface %s: Object\n"
"+(void) doit ;\n"
"@end\n\n"
"@implementation %s\n"
"+ (void) doit\n"
"{\n"
"#line 1\n"
"%s\n"
"}\n"
"@end",
header, tmpFile, tmpFile, body) ;
fflush(fp) ;
fclose(fp) ;
// compile the class defined in this file
sprintf(aStr, "cc -c -o %s /tmp/%s.o /tmp/%s.m 2> /tmp/%s.cc_errors",
NXGetDefaultValue([NXApp appName],"CompilerSwitches"),
tmpFile, tmpFile, tmpFile) ;
if(system(aStr)) // non-zero exit status == must report the errors
{ sprintf(aStr,"/tmp/%s.cc_errors",tmpFile) ;
[self appendFileToTranscript: aStr] ;
unlink(aStr) ;
NXRunAlertPanel("Eval","Compilation errors: see Transcript Window\n",
NULL,NULL,NULL) ;
sprintf(aStr,"/tmp/%s.m", tmpFile) ; unlink(aStr) ;
sprintf(aStr,"/tmp/%s.o",tmpFile) ; unlink(aStr) ;
return self ;
}
// dynamically link the class
moduleKnt = [libList count] ;
{ // block down to dynamically alloc moduleNames
char *moduleNames[moduleKnt + 2] ;
aStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
sprintf(aStr,"/tmp/%s.o",tmpFile) ;
moduleNames[0] = aStr ;
for(i = 1 ; i <= moduleKnt ; i++)
moduleNames[i] = (char *)[[libList objectAt: i] cString] ;
moduleNames[i] = NULL ;
if(objc_loadModules(moduleNames, aStream, NULL, NULL, NULL))
{ // load failed...
NXPutc(aStream,'\0') ;
NXGetMemoryBuffer(aStream, &cursor, &textLen, &maxLen);
[Eval printf: cursor];
NXRunAlertPanel("Eval","Load failed, see transcript\nfor details",
NULL,NULL,NULL) ;
}
else
{ // load succeeded...execute the method, at last!
objc_msgSend(objc_getClass(tmpFile), sel_getUid("doit")) ;
// now remove the module
objc_unloadModules(NULL, NULL) ;
}
}
NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
sprintf(aStr,"/tmp/%s.m",tmpFile) ; unlink(aStr) ;
sprintf(aStr,"/tmp/%s.o",tmpFile) ; unlink(aStr) ;
sprintf(aStr,"/tmp/%s.cc_errors",tmpFile) ; unlink(aStr) ;
return self ;
}
- evalObjCTranscript: sender ;
{ // evaluate the current transcript selection as ObjC
// get the selected text
NXSelPt start, end ;
char *textBuf ;
int textLen ;
[transcriptText getSel:&start :&end] ;
textLen = end.cp-start.cp ;
textBuf = (char *) alloca(textLen+1) ;
[transcriptText getSubstring:textBuf start:start.cp length:textLen] ;
[self evalObjC:textBuf length:textLen] ;
return self ;
}
- evalObjC:(id) pboard userData: (const char *) uBuf error: (char **) msg ;
{ // compile and run the selection
char *text ;
const char *const *types ;
int i, textLen ;
BOOL found = NO ;
// fetch the data from pasteboard
types = [pboard types] ;
for(i = 0 ; types[i]; i++)
{ if(!strcmp(types[i], NXAsciiPboardType))
{ found = YES ;
break ;
}
}
if(!found) // no ascii found...
return self ;
[pboard readType:NXAsciiPboardType data:&text length:&textLen];
if(!text || !textLen) // nothing there...
return self ;
else
return [self evalObjC: text length: textLen] ;
}
- evalPs: (id) pboard userData: (const char *) uBuf error: (char **) msg ;
{ // evaluate postscript from pasteboard
// fetch the data from pasteboard
const char *const *types ;
char *text, *buf ;
int textLen, i ;
BOOL found = NO ;
types = [pboard types] ;
for(i = 0 ; types[i]; i++)
{ if(!strcmp(types[i], NXAsciiPboardType))
{ found = YES ;
break ;
}
}
if(!found) // no ascii found...
return self ;
[pboard readType:NXAsciiPboardType data:&text length:&textLen];
if(!text || !textLen)
return self ;
// change text into a cstring
buf = alloca(textLen + 1) ;
strncpy(buf,text,textLen) ;
buf[textLen] = '\0' ;
[Eval ps: buf] ;
return self ;
}
- libAdd: sender ;
{ // add a library file's name to the list
// of libraries to be searched
id openPanel ;
char **theList, buf[256] ;
openPanel = [OpenPanel new] ;
if([openPanel runModalForTypes: libTypes])
{ theList = (char **) [openPanel filenames] ;
{ sprintf(buf,"%s/%s",[openPanel directory],
*theList++) ;
[libList addObject: [CString new:buf]] ;
}
[libBrowser loadColumnZero] ;
[self setDefaults: self] ;
}
return self ;
}
- libList ;
{ return libList ;
}
- libRemove: sender ;
{ // remove a library file's name to the list
// of libraries to be searched
int theRow ;
theRow = [[libBrowser matrixInColumn: 0] selectedRow] ;
if(theRow >= 0)
{ [[libList removeObjectAt: theRow] free] ;
[libBrowser loadColumnZero] ;
[self setDefaults: self] ;
}
return self ;
}
- setDefaults: sender ;
{ // write info from defaults panel to defaults
// database and to objects as needed
int i, knt ;
char frameString[256], libString[2048] ;
NXRect aFrame, bFrame ;
NXDefaultsVector theDefaults =
{ {"NXFont",NULL},
{"NXFontSize",NULL},
{"Frame",NULL},
{"GraphicsSize",NULL},
{"Libraries",NULL},
{"CompilerSwitches",NULL},
{NULL}
} ;
theDefaults[0].value = (char *) [fontName stringValue] ;
theDefaults[1].value = (char *) [fontSize stringValue] ;
// set the frame preference
[transcriptWindow getFrame: &aFrame] ;
[[transcriptWindow contentView] getFrame: &bFrame] ;
// Note: window's getFrame method returns the size of the
// window, whereas its sizeTo:: method sets the size of
// its contentView. Its really the contentView we want to save
aFrame.size = bFrame.size ;
sprintf(frameString,"%f %f %f %f\n",
aFrame.origin.x,aFrame.origin.y,
aFrame.size.width,aFrame.size.height) ;
theDefaults[2].value = frameString ;
// set the graphicsSize preference
theDefaults[3].value = (char *) [graphicsSize stringValue] ;
// set the Libraries preference
knt = [libList count] ;
libString[0] = '\0' ;
for(i = 0 ; i < knt ; i++)
{ strcat(libString,[[libList objectAt: i] cString]) ;
strcat(libString," ") ;
}
theDefaults[4].value = libString ;
// set the compiler options
theDefaults[5].value = (char *) [compilerSwitches stringValue] ;
NXWriteDefaults([NXApp appName], theDefaults) ;
return self ;
}
- setGraphicsScrollView: sender ;
{ // stash the docView in both our ivasr, transcriptGraphics,
// and the global var graphics.
transcriptGraphics = graphics = [sender docView] ;
graphicsScrollView = sender ;
return [self setUp] ;
}
- setGraphicsSize: sender ;
{ graphicsSize = sender ;
return [self setUp] ;
}
- setSplitView: anObject ;
{ // sets the splitview and attach its subpanels
splitView = anObject ;
return [self setUp] ;
}
- setTextScrollView: sender ;
{ // stash the docView in both our ivar, transcriptText,
// and the global var transcript.
transcriptText = text = [sender docView] ;
textScrollView = sender ;
return [self setUp] ;
}
- setUp ;
{ // if all my sockets have been filled,
// do some setup work...
if(splitView && textScrollView && graphicsScrollView && graphicsSize)
{ char aString[512] ;
const char *theAppName ;
const char *libraries ;
NXRect aRect ;
int i = 0, rval ;
// put views into splitview
[splitView addSubview:
[graphicsScrollView removeFromSuperview]] ;
[splitView addSubview:
[textScrollView removeFromSuperview]] ;
// set up the defaults
theAppName = [NXApp appName] ;
// setup the defaults
NXRegisterDefaults(theAppName, evalDefaults) ;
// copy info from defaults vector to UI objects
[fontName setStringValue: NXGetDefaultValue(theAppName,"NXFont")] ;
[fontSize setStringValue: NXGetDefaultValue(theAppName,"NXFontSize")] ;
[graphicsSize setStringValue: NXGetDefaultValue(theAppName,"GraphicsSize")] ;
// init the libList, display in browser
libList = [[List alloc] init] ;
libraries = NXGetDefaultValue(theAppName,"Libraries") ;
rval = sscanf(libraries,"%s",aString) ;
while(rval == 1)
{ [libList addObject: [CString new: aString]] ;
while(libraries[i] &&
!isspace(libraries[i++])) ; // find next library
rval = sscanf(&libraries[i],"%s",aString) ;
}
[libBrowser loadColumnZero] ;
// display the compiler options
[compilerSwitches setStringValue:
NXGetDefaultValue(theAppName,"CompilerSwitches")] ;
// now "apply" the defaults
[transcriptText setFont:
[Font newFont:NXGetDefaultValue(theAppName,"NXFont")
size:atof(NXGetDefaultValue(theAppName,"NXFontSize"))]] ;
sscanf(NXGetDefaultValue(theAppName,"Frame"),
"%f %f %f %f", &aRect.origin.x, &aRect.origin.y,
&aRect.size.width, &aRect.size.height) ;
[transcriptWindow sizeWindow: aRect.size.width :aRect.size.height] ;
[transcriptWindow moveTo:aRect.origin.x :aRect.origin.y] ;
// setup the graphics window
[graphics setUp] ;
}
return self ;
}
- showTranscript: sender ;
{ [transcriptWindow orderFront: self] ;
return self ;
}
- showTranscript: (id) pboard userData: (const char *) uBuf error: (char **) msg ;
{ [transcriptWindow orderFront: self] ;
return self ;
}
- terminate: sender ;
{ // make sure defaults are up-to-date
[self setDefaults: self] ;
return [super terminate: self] ;
}
- windowDidResize: sender ;
{ return [self setDefaults: self] ;
}
@end